﻿using System.Collections.Generic;
using System.Linq;

namespace Jeelu.Math
{
    /// <summary>
    ///     最大公约数（Greatest Common Divisor，简写为G.C.D.；或Highest Common Factor，简写为H.C.F.），
    ///     指某几个整数共有约数中最大的一个。
    /// </summary>
    public class GreatestCommonDivisor
    {
        private readonly List<long> _Array = new List<long>();

        public int CountOfArray
        {
            get { return _Array.Count; }
        }

        public void AddToArray(params long[] items)
        {
            foreach (long item in items)
                _Array.Add(item);
            _Array.Sort();
        }

        public void ClearToArray()
        {
            _Array.Clear();
        }

        public bool RemoveToArray(long item)
        {
            return _Array.Remove(item);
        }

        public int IndexOfArray(long item)
        {
            return _Array.IndexOf(item);
        }

        public void InsertToArray(int index, long item)
        {
            _Array.Insert(index, item);
            _Array.Sort();
        }

        public bool ClongArray(IEnumerable<long> newArray)
        {
            _Array.Clear();
            AddToArray((long[])newArray);
            return true;
        }

        /// <summary>获取当前类型的集合中的所有数的最大公约数。
        /// 本函数当前算法很一般，时间复杂度较高。
        /// </summary>
        public long GetGCD()
        {
            if (_Array.Count <= 1)
                throw new JeeluMathException("无必要对少于一个数求最小公约数。");

            var tmpList = new long[_Array.Count];
            long min = _Array[0];

            for (long j = min; j > 1; j--)
            {
                for (int i = 0; i < _Array.Count; i++)
                {
                    //将源数集合中的数对最小的数取余，并将取得的余数暂存在临时集合中
                    tmpList[i] = _Array[i]%j;
                }
                if (IsZeroForAll(tmpList))
                {
                    //如果临时余数集合中所有数均为零，则已找到了最小公约数。
                    return j;
                }
            }
            return 1;
        }

        private static bool IsZeroForAll(IEnumerable<long> array)
        {
            return array.All(t => t == 0);
        }
    }
}